package com.xinya.wanandroidclient.base

import com.xinya.wanandroidclient.http.ApiException
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.json.JSONException
import retrofit2.HttpException
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException


/**
 * typealias用于省略如泛型之类用不到的信息
 */
typealias Error = suspend (e: ApiException) -> Unit

/**
 *
 * @ClassName:      BaseRepository$
 * @Description:    java类作用描述
 * @Author:         xinya
 * @CreateDate:     2021/2/24$ 14:45$
 * @UpdateRemark:   更新内容
 * @Version:        1.0
 */
open class BaseRepository(
    private val coroutineScope: CoroutineScope
) {

    companion object {
        private const val TAG = "BaseRepository"
    }

    protected fun <T> launch(
        block: suspend () -> T,
        success: suspend (T) -> Unit,
        error: Error? = null
    ): Job {
        return coroutineScope.launch {
            runCatching {
                block()
            }.onSuccess {
                success(it)
            }.onFailure {
                it.printStackTrace()
                getApiException(it).apply {
                    error?.invoke(this)
                }
            }
        }
    }


    /**
     * 捕获异常信息
     */
    private fun getApiException(e: Throwable): ApiException {
        return when (e) {
            is UnknownHostException -> {
                ApiException("网络异常", -100)
            }
            is JSONException -> {//|| e is JsonParseException
                ApiException("数据异常", -100)
            }
            is SocketTimeoutException -> {
                ApiException("连接超时", -100)
            }
            is ConnectException -> {
                ApiException("连接错误", -100)
            }
            is HttpException -> {
                ApiException("http code ${e.code()}", -100)
            }
            is ApiException -> {
                e
            }
            /**
             * 如果协程还在运行，个别机型退出当前界面时，viewModel会通过抛出CancellationException，
             * 强行结束协程，与java中InterruptException类似，所以不必理会,只需将toast隐藏即可
             */
            is CancellationException -> {
                ApiException("", -10)
            }
            else -> {
                ApiException("未知错误", -100)
            }
        }
    }
}
